package com.jasonzhou.onetomanycontrol.service

import android.annotation.SuppressLint
import android.app.Service
import android.bluetooth.BluetoothA2dp
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Binder
import android.text.TextUtils
import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.jasonzhou.onetomanycontrol.base.AppContent
import com.jasonzhou.onetomanycontrol.bean.DataQueue
import com.jasonzhou.onetomanycontrol.constant.CHAR_ID
import com.jasonzhou.onetomanycontrol.constant.MessageConstant
import com.jasonzhou.onetomanycontrol.message.EventMessage
import com.jasonzhou.onetomanycontrol.util.Hex
import com.jasonzhou.onetomanycontrol.util.toIntE
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import java.util.Random
import java.util.UUID
import java.util.concurrent.TimeUnit
import kotlin.experimental.or
import kotlin.experimental.xor

/**
 * Created by Administrator on 2017/7/18.
 */
@SuppressLint("MissingPermission")
class SCCCommunication : Service(), BluetoothAdapter.LeScanCallback {


    private val mBinder = CommBinder()
    private lateinit var mBluetoothAdapter: BluetoothAdapter
    private lateinit var localBroadcast: LocalBroadcastManager
    private var mGatt: BluetoothGatt? = null
    private var timeoutDisposable: Disposable? = null
    private var scanList = mutableListOf<BluetoothDevice>()
    private var isRetryConnect = true

    private var checkVerify: Byte = 0

    companion object {
        const val SCAN_TIME = 10L
    }

    private var lastConnectDevice: BluetoothDevice? = null

    override fun onBind(intent: Intent) = mBinder

    /**
     * 发送数据队列
     */
    private val dataQueueList = arrayListOf<DataQueue>()

    /**
     * 当前发送状态，队列新增数据时如果未在发送则直接发送，反之则加入到队列中。
     */
    private var isSending = false
    var isAutoConnecting = false

    inner class CommBinder : Binder() {
        val communicationService: SCCCommunication
            get() = this@SCCCommunication
    }

    private val mReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent) {
            when (intent.action) {
                BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED -> {
                    val device: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
                    when (intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1)) {
                        BluetoothA2dp.STATE_CONNECTING -> {
                            Log.e("TAG", "音频连接中 ")
                        }

                        BluetoothA2dp.STATE_CONNECTED -> {
                            Log.e("TAG", "音频已连接 ")
                        }

                        BluetoothA2dp.STATE_DISCONNECTING -> {
                            Log.e("TAG", "音频断开中 ")
                        }

                        BluetoothA2dp.STATE_DISCONNECTED -> {
                            Log.e("TAG", "音频已断开 ")
//                            if (AppContent.instance.musicService.isPlay()) {
//                                AppContent.instance.musicService.pausePlay()
//                            }
                        }
                    }
                }

                BluetoothDevice.ACTION_BOND_STATE_CHANGED -> {
                    val bluetoothDevice = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
                    when (bluetoothDevice?.bondState) {
                        //配对失败
                        BluetoothDevice.BOND_NONE -> {
                        }
                        //正在配对
                        BluetoothDevice.BOND_BONDING -> {
                        }

                        BluetoothDevice.BOND_BONDED -> {
                            //配对成功
                            Log.e("TAG", String.format("配对成功: %s", bluetoothDevice.name))
                            BluetoothChatA2dpService.getInstance(this@SCCCommunication).connectA2dp(bluetoothDevice)
                        }
                    }
                }
            }
        }
    }


    /**
     * 初始化BluetoothGatt
     *
     * @return boolean
     */
    fun initialize(context: Context) {
        mBluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
        localBroadcast = LocalBroadcastManager.getInstance(context)
        registerReceiver(mReceiver, makeFilter())
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(mReceiver)
    }

    private fun makeFilter(): IntentFilter {
        val filter = IntentFilter()
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
        return filter
    }

    /**
     * 连接BluetoothGatt
     *
     * @param device
     * @return boolean
     */
    fun connect(device: BluetoothDevice) {
        isRetryConnect = true
        val address = device.address ?: return
        val mDevice = mBluetoothAdapter.getRemoteDevice(address) ?: return
        lastConnectDevice = mDevice
        mDevice.connectGatt(this, false, mGattCallback)
        timeoutDisposable = Observable.timer(10, TimeUnit.SECONDS).subscribe({}, {}, { disConnectDevice() })
    }

    fun disConnectDevice() {
        mGatt?.disconnect()
        dataQueueList.clear()
        timeoutDisposable?.dispose()
    }

    fun activeDisconnectDevice() {
        AppContent.instance.removeData(MessageConstant.KEY_AUTO_CONNECT_MAC)
        mGatt?.disconnect()
        dataQueueList.clear()
        timeoutDisposable?.dispose()
    }

    fun getDevice(): BluetoothDevice? = mGatt?.device

    /**
     * BLE回调函数
     */
    private val mGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
        //读取连接设备的RSSI值
        override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {
//            super.onReadRemoteRssi(gatt, rssi, status)
//            val iRssi = Math.abs(rssi)
//            val power = ((iRssi - 59) / (10 * 2.0)).toFloat()
        }

        override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            Log.e("TAG-A", "连接状态:$newState")
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                isAutoConnecting = false
                try {
                    Thread.sleep(500)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
                this@SCCCommunication.mGatt = gatt
                mGatt?.discoverServices()
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                dataQueueList.clear()
                isSending = false
                mGatt?.close()
                gatt.close()
                mGatt = null
                AppContent.instance.dataCtrl.device = null
                AppContent.instance.dataCtrl.deviceName = ""
                isAutoConnecting = false
//                if (AppContent.instance.musicService.isPlay()) {
//                    AppContent.instance.musicService.pausePlay()
//                }
                timeoutDisposable?.dispose()
                timeoutDisposable = null
                when (status) {
                    133 -> {
                        //重连重试一次
                        if (isRetryConnect) {
                            lastConnectDevice?.let { connect(it) }
                            isRetryConnect = false
                        } else {
                            //重试一次后仍然失败，走断开流程
                            EventBus.getDefault().post(EventMessage(MessageConstant.STATE_DISCONNECTED))
                            executeStartAutoContent()
                        }
                    }
                    //非需要重连情况，直接走断开流程
                    else -> {
                        EventBus.getDefault().post(EventMessage(MessageConstant.STATE_DISCONNECTED))
                        executeStartAutoContent()
                    }
                }
            }
        }

        override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
            super.onServicesDiscovered(gatt, status)
            if (status == BluetoothGatt.GATT_SUCCESS) {
                setNotificationDefault(gatt)
            }
        }


        override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
            super.onCharacteristicWrite(gatt, characteristic, status)
            //发送完成后如果队列中还有数据则取出继续发送，反正则置状态为false
            Log.e("TAG", "数据发送成功: " + characteristic.uuid.toString() + "-->" + Hex.byte2HexStr(characteristic.value))
            if (dataQueueList.isEmpty().not()) {
                isSending = true
                val dataQueue = dataQueueList.removeAt(0)
                innerWriteCharacteristic(dataQueue.uuid, dataQueue.data)
            } else {
                isSending = false
            }
        }

        override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
            super.onCharacteristicChanged(gatt, characteristic)
            handleReceiveData(characteristic)
        }

        override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
            super.onDescriptorWrite(gatt, descriptor, status)
            Log.e("TAG", "onDescriptorWrite: $status")
            if (status == 0) {
                timeoutDisposable?.dispose()
                sendVerifyData()
//                initSend()
//                EventBus.getDefault().post(EventMessage(MessageConstant.STATE_CONNECTED))
                AppContent.instance.dataCtrl.device = gatt.device
                AppContent.instance.dataCtrl.deviceName = gatt.device.name
                AppContent.instance.saveData(MessageConstant.KEY_AUTO_CONNECT_MAC, gatt.device.address)
            } else {
            }
        }
    }

    /**
     * 连上后获取配置信息
     */
    private fun initSend() {
    }

    @Synchronized
    private fun setNotificationDefault(gatt: BluetoothGatt) {
        val server = gatt.getService(CHAR_ID.UUID_MAP[CHAR_ID.SERVICE])
        if (server != null) {
            for (characteristic in server.characteristics) {
                val success = gatt.setCharacteristicNotification(characteristic, true)
                if (success) {
                    characteristic.descriptors.forEach {
                        it.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
                        gatt.writeDescriptor(it)
                    }
                }
            }
        }
    }

    /**
     * 写指定设备指定的通道GattCharacteristic操作
     */
    private fun innerWriteCharacteristic(uuid: UUID?, data: ByteArray?) {
        this@SCCCommunication.mGatt?.apply {
            val characteristic = getService(CHAR_ID.UUID_MAP[CHAR_ID.SERVICE]).getCharacteristic(uuid)
            characteristic.let { ct ->
                val charaProp = ct.properties
                if (charaProp or BluetoothGattCharacteristic.PERMISSION_WRITE > 0) {
                    ct.value = data
                    this.writeCharacteristic(ct)
                }
            }
        }
    }

    /**
     * 写指定设备指定的通道GattCharacteristic操作
     */
    fun writeCharacteristic(uuid: UUID?, data: ByteArray) {
        if (uuid == null) return
        mGatt?.apply {
            getService(CHAR_ID.UUID_MAP[CHAR_ID.SERVICE])?.getCharacteristic(uuid) ?: return
            dataQueueList.add(DataQueue(device, data, uuid))
            if (isSending.not()) {
                isSending = true
                val dataQueue = dataQueueList.removeAt(0)
                innerWriteCharacteristic(dataQueue.uuid, dataQueue.data)
            }
        }
    }

    private fun handleReceiveData(characteristic: BluetoothGattCharacteristic) {
        Log.e("TAG-A", "origin:${Hex.byte2HexStr(characteristic.value)}")
        val data = characteristic.value
        try {
            when (data[0].toIntE()) {

            }
        } catch (e: Exception) {

        }

    }

    private fun sendVerifyData() {
        val randomTemp = ByteArray(6)
        val random = Random()
        random.nextBytes(randomTemp)
        calcVerify(randomTemp)
//        SendHelper.sendHandShake(randomTemp)
    }

    private fun calcVerify(data: ByteArray) {
        checkVerify = (data[2] or data[4]) xor data[1]
    }

    fun executeStartAutoContent() {
        val mac = AppContent.instance.getString(MessageConstant.KEY_AUTO_CONNECT_MAC, "")
        if (TextUtils.isEmpty(mac)) {
            return
        }
        if (AppContent.instance.getBoolean(MessageConstant.KEY_IS_AUTO_CONNECT, true).not()) {
            return
        }
        startScan()
    }

    fun executeStopAutoContent() {
        stopScan()
    }

    var isScanning = false
    private var disposable: Disposable? = null
    private fun stopScan() {
        isScanning = false
        isAutoConnecting = false
        BluetoothAdapter.getDefaultAdapter().stopLeScan(this)
        disposable?.dispose()
    }

    private fun startScan() {
        val mac = AppContent.instance.getString(MessageConstant.KEY_AUTO_CONNECT_MAC, "")
        Log.e("TAG-A", "执行回连扫描 ${mac}")
        scanList.clear()
        isScanning = true
        BluetoothAdapter.getDefaultAdapter().stopLeScan(this)
        BluetoothAdapter.getDefaultAdapter().startLeScan(this)
        disposable = Observable.timer(SCAN_TIME, TimeUnit.SECONDS).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
            .subscribe({}, {}, {
                stopScan()
            })
    }

    override fun onLeScan(device: BluetoothDevice, rssi: Int, scanRecord: ByteArray) {
        if (scanList.contains(device)) {
            return
        }
        Log.e("TAG-A", "onLeScan: ${device.name} --  ${device.address}")
        scanList.add(device)
        if (mGatt != null) {
            return
        }
        if (autoConnect(device)) {
            stopScan()
        }
    }

    private fun autoConnect(device: BluetoothDevice): Boolean {
        if (isAutoConnecting) {
            return false
        }
        val mac = AppContent.instance.getString(MessageConstant.KEY_AUTO_CONNECT_MAC, "")
        if (AppContent.instance.getBoolean(MessageConstant.KEY_IS_AUTO_CONNECT, true).not()) {
            return false
        }
        if (TextUtils.equals(device.address, mac).not()) {
            return false
        }
        if (TextUtils.isEmpty(mac)) {
            Log.e("TAG-A", "autoConnect: 连接地址为空")
            return false
        }
        val tempDevice = mBluetoothAdapter.getRemoteDevice(mac)
        if (tempDevice == null) {
            Log.e("TAG-A", "autoConnect: 生成设备为空")
            return false
        }
        if (AppContent.instance.dataCtrl.device != null) {
            Log.e("TAG-A", "当前已有设备连接，无需回连")
            return false
        }
        Log.e("TAG-A", "搜索到符合设备，执行回连")
        connect(tempDevice)
        isAutoConnecting = true
        EventBus.getDefault().post(EventMessage(MessageConstant.ACTION_START_AUTO_CONNECT))
        return true
    }
}
